﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using AzukiMap.Layer;
using AzukiMap.Tools.Logger;
using GeoAPI.Geometries;

namespace AzukiMap.Renderer
{
    public abstract class RasterRendererCore : IRasterRendererCore
    {
        private MapLayer _layer;
        protected const double TileAdjustPixel = 1;

        public RasterRendererCore(MapLayer layer)
        {
            _layer = layer;
        }

        public double RendererAccuracyPixel
        {
            get; set;
        }

        #region IRasterRendererCore Members

        public abstract bool IsFitToDraw(GeoAPI.Geometries.IPolygon imagePolyOnMap, ImageMidPoints imageMidpointsOnMap);
        public abstract IList<FrameworkElement> CreateImages(Uri imageUri, GeoAPI.Geometries.IPolygon imagePoly);

        #endregion

        protected bool IsAccuratedPoint(Point imageMidPoint, Point correctMidpoint)
        {
            double gap = Math.Sqrt(Math.Pow((imageMidPoint.X - correctMidpoint.X), 2)
                                   + Math.Pow((imageMidPoint.Y - correctMidpoint.Y), 2));
            return gap < RendererAccuracyPixel;
        }
        
        protected void SetImageOrigin(Image img, IPolygon imagePoly)
        {
            ICoordinate tl = imagePoly.Coordinates[0];
            IPoint pixelOrigin = _layer.MapCoord.GetPixPointFromGeo(tl.X, tl.Y);
            img.SetValue(Canvas.LeftProperty, pixelOrigin.X);
            img.SetValue(Canvas.TopProperty, pixelOrigin.Y);
        }

        protected double GetImageWidth(double imageGeoWidth)
        {
            return imageGeoWidth / _layer.MapCoord.ScreenScale + AzukiMapSettings.TILE_JOINT_LINE_ADJUST_WIDTH;
        }

        protected double GetImageHeight(double imageGeoHeight)
        {
            return imageGeoHeight / _layer.MapCoord.ScreenScale + AzukiMapSettings.TILE_JOINT_LINE_ADJUST_WIDTH;
        }

        protected double GetGeoWidth(IPolygon imagePoly)
        {
            return imagePoly.EnvelopeInternal.Width;
        }

        protected double GetGeoHeight(IPolygon imagePoly)
        {
            return imagePoly.EnvelopeInternal.Height;
        }

        protected Point GetPixPoint(ICoordinate coord)
        {
            IPoint pixPoint = _layer.MapCoord.GetPixPointFromGeo(coord.X, coord.Y);
            var p = new Point(pixPoint.X, pixPoint.Y);

            return p;
        }
        protected Point GetPointOnImage(IPoint p, IPoint origin, double perPixX, double perPixY)
        {
            double x = (p.X - origin.X) / perPixX;
            double y = (origin.Y - p.Y) / perPixY;
            return new Point(x, y);
        }

        protected Point GetMidpoint(Point p1, Point p2)
        {
            double x = (p1.X + p2.X) / 2;
            double y = (p1.Y + p2.Y) / 2;
            return new Point(x, y);
        }

        // TODO:
#if SILVERLIGHT
        protected void source_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            Logger.Error("Fail to load a image: " + ((BitmapImage)sender).UriSource.ToString() );
            //throw new NotImplementedException();
        }
#else
        protected void source_DownloadFailed(object sender, ExceptionEventArgs e)
        {
            Logger.Error("Fail to load a image: " + ((BitmapImage)sender).UriSource.ToString() );
            //throw new NotImplementedException();
        }
#endif
    }
}
